
`include "defines.v"

module csr(
    input  wire clk,
	input  wire rst,
	
	input  wire  [11  : 0] w_addr,
	input  wire  [`REG_BUS-1 : 0] w_data,
	input  wire 		   w_ena,
	
	input  wire  [11  : 0] r_addr,
	output wire  [`REG_BUS-1 : 0] r_data,

	output wire r_exception,
	output wire w_exception
	
    );

	wire [63:0] misa;// R W, implement just R
	wire w_misa, r_misa;
	assign w_misa = w_addr == 12'h301;
	assign r_misa = r_addr == 12'h301;
	assign misa = 64'b10_000000000000000000000000000000000000_00000000000000000100000000;


	wire [63:0] mvendorid;// R only
	wire r_mvendorid;
	assign r_mvendorid = r_addr == 12'hf11;
	assign mvendorid = 64'b0;


	wire [63:0] marchid;// R only
	wire r_marchid;
	assign r_marchid = r_addr == 12'hf12;
	assign marchid = 64'b0;


	wire [63:0] mimpid;// R only
	wire r_mimpid;
	assign r_mimpid = r_addr == 12'hf13;
	assign mimpid = 64'b0;


	wire [63:0] mhartid;// R only
	wire r_mhartid;
	assign r_mhartid = r_addr == 12'hf14;
	assign mhartid = 64'b0;


	reg [63:0] mstatus;
	wire [63:0] mstatus_wire;
	wire r_mstatus, w_mstatus;
	assign r_mstatus = r_addr == 12'h300;
	assign w_mstatus = w_addr == 12'h300;
	assign mstatus_wire = w_mstatus ? {w_data[16:15]==2'b11 | w_data[14:13]==2'b11, 27'b0, w_data[35:32], 9'b0, w_data[22:0]} : mstatus;
	always @(posedge clk) begin
		if(rst) mstatus <= 64'b0;
		else mstatus <= mstatus_wire;
	end


	reg [63:0] mtvec;
	wire [63:0] mtvec_wire;
	wire r_mtvec, w_mtvec;
	assign r_mtvec = r_addr == 12'h305;
	assign w_mtvec = w_addr == 12'h305;
	assign mtvec = w_mtvec ? w_data : mtvec;
	always @(posedge clk) begin
		if(rst) mtvec <= 64'b0;
		else mtvec <= mtvec_wire;
	end


	reg [63:0] mstratch;
	wire [63:0] mstratch_wire;
	wire r_mstratch, w_mstratch;
	assign r_mstratch = r_addr == 12'h340;
	assign w_mstratch = w_addr == 12'h340;
	assign mstratch = w_mstratch ? w_data : mstratch;
	always @(posedge clk) begin
		if(rst) mstratch <= 64'b0;
		else mstratch <= mstratch_wire;
	end

    reg [63:0] mcycle;
    wire r_mcycle, w_mcycle;
    assign r_mcycle = r_addr == 12'hb00;
    assign w_mcycle = w_addr == 12'hb00;
    always @(posedge clk) begin
        if(rst) mcycle <= 64'b0;
        else mcycle <= w_mcycle ? w_data : mcycle + 1'b1;
    end

	assign r_data = {64{r_misa}}      & misa      | 
					{64{r_mvendorid}} & mvendorid |
					{64{r_marchid}}   & marchid   |
					{64{r_mimpid}}    & mimpid    |
					{64{r_mhartid}}   & mhartid   |
					{64{r_mstatus}}   & mstatus   |
					{64{r_mtvec}}     & mtvec     |
					{64{r_mstratch}}  & mstratch  |
					{64{r_mcycle}}    & mcycle    ;

	


endmodule
